#define _WIN32_IE 0x0600
#define _WIN32_WINNT 0x0A00
#include "windows_format.h"
#include "ezctrl.h"
#include "res.hpp"
#include "version.h"
#include "easy_listview.h"

//data processing
struct CLDATE {
	int y;
	int m;
	int d;
};
struct STUDENT {
	char name[200];
	int group;
};
struct LOG {
	CLDATE logdate;
	STUDENT logstu;
	double mark;
	char rsn[300];
	bool bToBeDel;
	bool bProblem;
	time_t tRecordTime;
	time_t tLastEditTime;
};


//log actions
int ReadLog(LOG log[1000]) {
	for(int i=0; i<=999; i++) {
		log[i]= {0};
	}
	char line[6000][200]= {0};
	FILE *pF=fopen(LOGFILE,"r");
	if(pF==NULL)return -1;
	int iCount;
	for(int i=0; !feof(pF)&&i<6000; i++) {
		fgets(line[i],200,pF);
		if(line[i][strlen(line[i])-1]=='\n') {
			line[i][strlen(line[i])-1]='\0';
		}
		iCount=i;
	}
	fclose(pF);

	int iLogNum=0;

	for(int i=0; i<=6000&&strlen(line[i])>=1; i++) {
		if(strcmp(line[i],XXX)==0) {
			sscanf(line[i+1],"%d/%d/%d/",
			       &log[iLogNum].logdate.y,
			       &log[iLogNum].logdate.m,
			       &log[iLogNum].logdate.d);
			strcpy(log[iLogNum].logstu.name,line[i+2]);
			sscanf(line[i+3],"%d",&log[iLogNum].logstu.group);
			sscanf(line[i+4],"%lf",&log[iLogNum].mark);
			strcpy(log[iLogNum].rsn,line[i+5]);
			sscanf(line[i+6],"%d",&log[iLogNum].tRecordTime);
			sscanf(line[i+7],"%d",&log[iLogNum].tLastEditTime);
			if(strcmp(line[i+6],XXX)==0) {
				log[iLogNum].tRecordTime=log[iLogNum].tLastEditTime=0;
			}
			iLogNum++;
		}
	}

	return iLogNum;
}

int ImportLog(LOG log[1000],const char* szFileName) {
	int iNumExist=0;
	//已经存在的日志数量
	for(int i=0; i<=999; i++) {
		iNumExist=i;
		if(strlen(log[i].logstu.name)<1) {
			break;
		}
	}

	char line[6000][200]= {0};
	FILE *pF=fopen(szFileName,"r");
	if(pF==NULL)return -1;
	int iCount;
	for(int i=0; !feof(pF)&&i<6000; i++) {
		fgets(line[i],200,pF);
		if(line[i][strlen(line[i])-1]=='\n') {
			line[i][strlen(line[i])-1]='\0';
		}
		iCount=i;
	}
	fclose(pF);

	int iLogNum=iNumExist;
	for(int i=0; i<6000&&strlen(line[i])>=1; i++) {
		if(iLogNum>=999)break;
		if(strcmp(line[i],XXX)==0) {
			sscanf(line[i+1],"%d/%d/%d/",
			       &log[iLogNum].logdate.y,
			       &log[iLogNum].logdate.m,
			       &log[iLogNum].logdate.d);
			strcpy(log[iLogNum].logstu.name,line[i+2]);
			sscanf(line[i+3],"%d",&log[iLogNum].logstu.group);
			sscanf(line[i+4],"%lf",&log[iLogNum].mark);
			strcpy(log[iLogNum].rsn,line[i+5]);
			sscanf(line[i+6],"%d",&log[iLogNum].tRecordTime);
			sscanf(line[i+7],"%d",&log[iLogNum].tLastEditTime);
			if(strcmp(line[i+6],XXX)==0) {
				log[iLogNum].tRecordTime=log[iLogNum].tLastEditTime=0;
			}
			iLogNum++;
		}
	}

	return iLogNum;
}

int WriteLog(LOG Log) {
	FILE *pfLog=fopen(LOGFILE,"a");
	if(pfLog==NULL)return -1;
	if(strcmp(Log.logstu.name,XXX)==0) {
		strcpy(Log.logstu.name,"XXX");
	}
	if(strcmp(Log.rsn,XXX)==0) {
		strcpy(Log.rsn,"XXX");
	}
	fprintf(pfLog,"###\n%d/%d/%d\n%s\n%d\n%.1f\n%s\n%d\n%d\n"
	        ,Log.logdate.y,Log.logdate.m,Log.logdate.d,
	        Log.logstu.name,Log.logstu.group,Log.mark,Log.rsn,
	        Log.tRecordTime,Log.tLastEditTime);
	fclose(pfLog);
	return 0;
}

int WriteLog1000(LOG log[1000]) {
	FILE *pfLog=fopen(LOGFILE,"w");
	if(pfLog==NULL)return -1;
	for(int i=0; i<=1000&&strlen(log[i].logstu.name)!=0; i++) {
		if(log[i].bToBeDel==true)continue;//if be deleted, skip
		if(strcmp(log[i].logstu.name,XXX)==0) {
			strcpy(log[i].logstu.name,"XXX");
		}
		if(strcmp(log[i].rsn,XXX)==0) {
			strcpy(log[i].rsn,"XXX");
		}
		fprintf(pfLog,"###\n%d/%d/%d\n%s\n%d\n%.1f\n%s\n%d\n%d\n"
		        ,log[i].logdate.y,log[i].logdate.m,log[i].logdate.d,
		        log[i].logstu.name,log[i].logstu.group,log[i].mark,log[i].rsn,
		        log[i].tRecordTime,log[i].tLastEditTime);
	}
	fclose(pfLog);
	return 0;
}

int WriteLog1000(LOG log[1000],const char* szFileName) {
	FILE *pfLog=fopen(szFileName,"w");
	if(pfLog==NULL)return -1;
	for(int i=0; i<=1000&&strlen(log[i].logstu.name)!=0; i++) {
		if(log[i].bToBeDel==true)continue;//if be deleted, skip
		fprintf(pfLog,"###\n%d/%d/%d\n%s\n%d\n%.1f\n%s\n%d\n%d\n"
		        ,log[i].logdate.y,log[i].logdate.m,log[i].logdate.d,
		        log[i].logstu.name,log[i].logstu.group,log[i].mark,log[i].rsn,
		        log[i].tRecordTime,log[i].tLastEditTime);
	}
	fclose(pfLog);
	return 0;
}

//statistics
struct GROUP {
	bool bGroupUsed;
	unsigned int uiGroupNum;
	double dMark;
};
struct STUDENT_MARKED {
	STUDENT stu;
	double dMark;
};

int Statistics(char szOut[2000],LOG log[1000],CLDATE dtStart,CLDATE dtEnd) {
	strcpy(szOut,"\0");
	GROUP group[100]= {0};//初始化
	int idtLog;
	int idtStart=dtStart.y*10000+dtStart.m*100+dtStart.d,
	    idtEnd=dtEnd.y*10000+dtEnd.m*100+dtEnd.d;//将日期这样保存成整数来判断

	if(idtEnd<idtStart) {
		strcpy(szOut,
		       "错误：结束时间在开始时间之前，或许你可以考虑交换开始和结束时间。");
		FILE *pTmp=fopen(STA_OUT,"w");
		if(pTmp!=NULL) {
			fprintf(pTmp,szOut);
		}
		fclose(pTmp);
		return -1;
	}

	for(int i=0; i<=99; i++) {
		group[i].uiGroupNum=i+1;//初始化组号
	}

	for(int i=0; i<=999; i++) {
		for(int i1=0; i1<=99; i1++) {
			//同上的方法处理日期
			idtLog=log[i].logdate.y*10000+
			       log[i].logdate.m*100+log[i].logdate.d;
			if(idtLog>=idtStart&&idtLog<=idtEnd) {
				if(log[i].logstu.group==group[i1].uiGroupNum) {
					group[i1].bGroupUsed=true;
					group[i1].dMark+=log[i].mark;
					break;
				}
			}
		}
	}
	for(int i=0; i<=99; i++) {
		if(!group[i].bGroupUsed)continue;
	}
	//将有用的小组分离出来
	GROUP group_used[100]= {0},group_temp= {0}; //仅保存用了的小组
	int iMaxCount=0;//并保存下有用的小组数量

	for(int i=0; i<=99; i++) {
		if(group[i].bGroupUsed) {
			group_used[iMaxCount]=group[i];
			iMaxCount++;
		}
	}
	if(iMaxCount==0) {
		strcpy(szOut,"错误：指定日期内没有任何有效的日志。\r\n\
请注意这里的日期指的是日志记录中填写的日期，而不是日志的记录时间或修改时间。");
		FILE *pTmp=fopen(STA_OUT,"w");
		if(pTmp!=NULL) {
			fprintf(pTmp,szOut);
		}
		fclose(pTmp);
		return -1;
	}
	for(int i=0; i<=iMaxCount-1; i++) {
		for(int j=0; j<i; j++) {
			if(group_used[i].dMark>=group_used[j].dMark) {
				group_temp=group_used[i];
				group_used[i]=group_used[j];
				group_used[j]=group_temp;
			}
		}
	}
	char tmp[1600]= {0};

	strcat(szOut,"统计结果...\r\n");
	sprintf(tmp,"从 %d年%d月%d日 到 %d年%d月%d日。\r\n",
	        dtStart.y,dtStart.m,dtStart.d,dtEnd.y,dtEnd.m,dtEnd.d);
	strcat(szOut,tmp);
	strcat(szOut,"=====================================\r\n");
	strcat(szOut,"排名        \t小组  \t\t分数\r\n");
	strcat(szOut,"-------------------------------------\r\n");

	for(int i=0; i<=iMaxCount-1; i++) {

		char isBinglie[100]= {0};
		int iMingci=0;
		//处理并列
		if((i!=0)
		        &&(group_used[i].dMark==group_used[i-1].dMark)) {
			strcpy(isBinglie,"(并列)");
		} else {
			strcpy(isBinglie,"      ");
		}
		if(i==0) {
			strcpy(isBinglie,"      ");
		}

		iMingci=i+1;
		for(int i2=i;
		        (group_used[i2].dMark==group_used[i2-1].dMark)&&i2>=1; i2--) {
			iMingci=i2;
		}


		sprintf(tmp,"第%2d名%s\t第%2d组\t\t%+.1f\r\n",
		        iMingci,
		        isBinglie,
		        group_used[i].uiGroupNum,group_used[i].dMark);
		strcat(szOut,tmp);
	}
	strcat(szOut,"=====================================\r\n");
	strcat(szOut,"统计时间：");
	time_t t=time(NULL);
	tm local=*localtime(&t);
	strcat(szOut,asctime(&local));
	strcat(szOut,"。\r\n按 统计明细... 按钮可以通过表格查看每个人的分数。\r\n\
按 保存统计结果... 按钮可以保存统计报告或明细。");

	//统计明细：统计每个人
	FILE *pOut=fopen(STA_OUT,"w");

	STUDENT stu[1000]= {0};
	STUDENT_MARKED stum_used[1000]= {0};
	for(int i=0; i<=999; i++)stu[i]=log[i].logstu;
	for(int i=0; i<=999; i++) {
		for(int j=0; j<i; j++) {
			if(strcmp(stu[j].name,stu[i].name)==0&&stu[j].group==stu[i].group) {
				stu[i]= {0};
				break;//去掉重复的学生
			}
		}
	}
	int iStuCount=0;
	for(int i=0; i<=999; i++) {
		if(strlen(stu[i].name)!=0) {
			stum_used[iStuCount].stu=stu[i];
			iStuCount++;
		}
	}//同上小组

	for(int i=0; i<=iStuCount-1; i++) {
		for(int j=0; j<=999; j++) {
			int iDate=log[j].logdate.y*10000+log[j].logdate.m*100+log[j].logdate.d;
			if(strcmp(stum_used[i].stu.name,log[j].logstu.name)==0
			        &&iDate>=idtStart&&iDate<=idtEnd) {
				stum_used[i].dMark+=log[j].mark;
			}
		}
	}

	if(pOut==NULL) return -2;
	fprintf(pOut,"班级日志 分数统计明细\n");
	fprintf(pOut,"从 %d年%d月%d日 到 %d年%d月%d日\n",
	        dtStart.y,dtStart.m,dtStart.d,dtEnd.y,dtEnd.m,dtEnd.d);
	fprintf(pOut,"排名,小组,人员,分数\n");
	for(int i=0; i<=iMaxCount-1; i++) {
		char isBinglie[100]= {0};
		int iMingci=0;
		//处理并列
		if((i!=0)
		        &&(group_used[i].dMark==group_used[i-1].dMark)) {
			strcpy(isBinglie,"(并列)");
		} else {
			strcpy(isBinglie,"      ");
		}
		if(i==0) {
			strcpy(isBinglie,"      ");
		}

		iMingci=i+1;
		for(int i2=i;
		        (group_used[i2].dMark==group_used[i2-1].dMark)&&i2>=1; i2--) {
			iMingci=i2;
		}


		fprintf(pOut,"第%d名%s,第%d组,,%+.1f\n",
		        iMingci,
		        isBinglie,group_used[i].uiGroupNum,group_used[i].dMark);
		for(int j=0; j<=iStuCount-1; j++) {
			if(stum_used[j].stu.group==group_used[i].uiGroupNum&&stum_used[j].dMark!=0) {
				fprintf(pOut,",,%s,%+.1f\n",stum_used[j].stu.name,stum_used[j].dMark);
			}
		}

	}

	fprintf(pOut,"统计时间：%s",ctime(&t));
	fclose(pOut);

	return 0;
}

//namelist
int ReadNamelist(STUDENT stu[200]) {
	FILE *pName=fopen(NAMELIST,"r");
	char line[200][200],data[400][200];
	if(pName==NULL)return -10;
	int iNum=-1;
	do {
		iNum++;
		fgets(line[iNum],200,pName);
	} while(!feof(pName));
	cout<<iNum;
	for(int i=0; i<=iNum; i++) {
		if(line[i][strlen(line[i])-1]=='\n') {
			line[i][strlen(line[i])-1]='\0';
		}
	}//去掉行尾的空格
	fclose(pName);
	for(int i=0; i<=iNum-1; i++) {
		sscanf(line[i],"%d,%[^,]",&stu[i].group,stu[i].name);//读取：读到下一个逗号为止
	}
	return iNum;//返回读取到的数量，从0开始计数的，要加1
}

//config file
struct CLCONFIG {
	bool bDpiAware;
	bool bShowSB;
	bool bHideDev;

	bool bDisableAutoGuide;
	bool bDisableAutoTip;

	bool bRecordTime;

	int iOpenTab;
};

int DefToConfig() {
	FILE *pWr=fopen(CONFIG,"w");
	if(pWr==NULL)return -1;
	fprintf(pWr,"bDpiAware=1\n\
bShowSB=0\n\
bHideDev=0\n\
bDisableAutoGuide=0\n\
bDisableAutoTip=0\n\
bRecordTime=1\n\
iOpenTab=107");
	fclose(pWr);
	return 0;
}


int ReadConfig(CLCONFIG* clc) {
	FILE *pRd=fopen(CONFIG,"r");
	if(pRd==NULL) {
		return -1;
	}
	int r=fscanf(pRd,"bDpiAware=%d\n\
bShowSB=%d\n\
bHideDev=%d\n\
bDisableAutoGuide=%d\n\
bDisableAutoTip=%d\n\
bRecordTime=%d\n\
iOpenTab=%d"
	             ,&clc->bDpiAware,&clc->bShowSB,
	             &clc->bHideDev,&clc->bDisableAutoGuide
	             ,&clc->bDisableAutoTip,&clc->bRecordTime,
	             &clc->iOpenTab);
	fclose(pRd);
	if(r!=7) {
		return -1;
	}
	return 0;
}

int WriteConfig(CLCONFIG clc) {
	FILE *pWr=fopen(CONFIG,"w");
	if(pWr==NULL)return -1;
	fprintf(pWr,"bDpiAware=%d\n\
bShowSB=%d\n\
bHideDev=%d\n\
bDisableAutoGuide=%d\n\
bDisableAutoTip=%d\n\
bRecordTime=%d\n\
iOpenTab=%d",
	        clc.bDpiAware,
	        clc.bShowSB,
	        clc.bHideDev,
	        clc.bDisableAutoGuide,
	        clc.bDisableAutoTip,
	        clc.bRecordTime,
	        clc.iOpenTab);
	fclose(pWr);
	return 0;
}

//gui
struct GROUPCTRL {
	EZCTRL Ctrl;
	int ctrlGroup;
};

int LoadDateToday(CLDATE *dt) {
	time_t tNow=time(NULL);
	tm tmNow=*localtime(&tNow);
	dt->y=tmNow.tm_year+1900;
	dt->m=tmNow.tm_mon+1;
	dt->d=tmNow.tm_mday;
	return 0;
}

int LoadDate_2WeeksAgo(CLDATE *dt) {
	time_t tNow=time(NULL);
	tNow-=14*24*60*60;
	tm tmNow=*localtime(&tNow);
	dt->y=tmNow.tm_year+1900;
	dt->m=tmNow.tm_mon+1;
	dt->d=tmNow.tm_mday;
	return 0;
}

int TestNamelist(void) {
	FILE *pF=fopen(NAMELIST,"r");
	if(pF==NULL) {
		return 0;
	} else {
		fclose(pF);
		return 1;
	}
}

int RandomStatistics(char szRst[500],LOG Log[1000]) {
	char szTmp[500]= {0};

	int idtStart=20000101,idtEnd=21000101;

	int iDate[1000]= {0};

	GROUP group[100]= {0},group_used[100]= {0},group_temp= {0}; //仅保存用了的小组
	int iMaxCount=0;//并保存下有用的小组数量
	for(int i=0; i<=99; i++) {
		group[i].uiGroupNum=i+1;//初始化组号
	}

	int iLogMax=ReadLog(Log);
	if(iLogMax<1) {
		strcpy(szRst,"没有有效的日志，无法统计。");
		return -1;
	}
	for(int i=0; i<=iLogMax-1; i++) {
		iDate[i]=Log[i].logdate.y*10000+Log[i].logdate.m*100+Log[i].logdate.d;
	}

	for(int i=0; i<=iLogMax-1; i++) {
		for(int j=0; j<i; j++) {
			int tmp;
			if(iDate[j]>iDate[i]) {
				tmp=iDate[i];
				iDate[i]=iDate[j];
				iDate[j]=tmp;
			}
		}
	}
	idtStart=iDate[0];
	idtEnd=iDate[iLogMax-1];

	for(int i=0; i<=999; i++) {
		for(int i1=0; i1<=99; i1++) {
			//同上的方法处理日期
			int idtLog=Log[i].logdate.y*10000+
			           Log[i].logdate.m*100+Log[i].logdate.d;
			if(idtLog>=idtStart&&idtLog<=idtEnd) {
				if(Log[i].logstu.group==group[i1].uiGroupNum) {
					group[i1].bGroupUsed=true;
					group[i1].dMark+=Log[i].mark;
					break;
				}
			}
		}
	}
	for(int i=0; i<=99; i++) {
		if(!group[i].bGroupUsed)continue;
	}
	for(int i=0; i<=99; i++) {
		if(group[i].bGroupUsed) {
			group_used[iMaxCount]=group[i];
			iMaxCount++;
		}
	}

	for(int i=0; i<=iMaxCount; i++) {
		for(int j=0; j<i; j++) {
			if(group_used[j].dMark<group_used[i].dMark) {
				GROUP group_tmp;
				group_tmp=group_used[j];
				group_used[j]=group_used[i];
				group_used[i]=group_tmp;
			}
		}
	}

	STUDENT stu[1000]= {0};
	STUDENT_MARKED stum_used[1000]= {0};
	for(int i=0; i<=999; i++)stu[i]=Log[i].logstu;

	for(int i=0; i<=999; i++) {
		for(int j=0; j<i; j++) {
			if(strcmp(stu[j].name,stu[i].name)==0) {
				stu[i]= {0};
				break;//去掉重复的学生
			}
		}
	}
	int iStuCount=0;
	for(int i=0; i<=999; i++) {
		if(strlen(stu[i].name)!=0) {
			stum_used[iStuCount].stu=stu[i];
			iStuCount++;
		}
	}//同上小组

	for(int i=0; i<=iStuCount-1; i++) {
		for(int j=0; j<=999; j++) {
			int iDate=Log[j].logdate.y*10000+Log[j].logdate.m*100+Log[j].logdate.d;
			if(strcmp(stum_used[i].stu.name,Log[j].logstu.name)==0
			        &&iDate>=idtStart&&iDate<=idtEnd) {
				stum_used[i].dMark+=Log[j].mark;
			}
		}
	}

	for(int i=1; i<=iStuCount-1; i++) {
		for(int j=0; j<i; j++) {
			STUDENT_MARKED stum_tmp;
			if(stum_used[j].dMark<stum_used[i].dMark) {
				stum_tmp=stum_used[j];
				stum_used[j]=stum_used[i];
				stum_used[i]=stum_tmp;
			}
		}
	}

	srand(time(NULL)+clock());

	int iRnd=rand();
	switch(iRnd%5) {
		case 0: {
			srand(time(NULL)+clock());
			int iRndStu=rand()%iStuCount;
			sprintf(szTmp,"第 %d 组的 %s 同学一共%s了 %.1f 分。",
			        stum_used[iRndStu].stu.group,
			        stum_used[iRndStu].stu.name,
			        (stum_used[iRndStu].dMark>=0)?"得":"扣",
			        (stum_used[iRndStu].dMark>=0)?stum_used[iRndStu].dMark:(-stum_used[iRndStu].dMark));
			break;
		}
		case 1: {
			srand(time(NULL)+clock());
			int iRndGp=rand()%iMaxCount;
			sprintf(szTmp,"第 %d 组一共%s了 %.1f 分。",
			        group_used[iRndGp].uiGroupNum,
			        (group_used[iRndGp].dMark>=0)?"得":"扣",
			        (group_used[iRndGp].dMark>=0)?group_used[iRndGp].dMark:(-group_used[iRndGp].dMark));
			break;
		}
		case 2: {
			srand(time(NULL)+clock());
			int iRndStu=rand()%iStuCount;
			sprintf(szTmp,"第 %d 组的 %s 同学的得分排在第 %d 名。",
			        stum_used[iRndStu].stu.group,
			        stum_used[iRndStu].stu.name,
			        iRndStu+1);
			break;
		}
		case 3: {
			srand(time(NULL)+clock());
			int iRndStu=rand()%iStuCount;
			sprintf(szTmp,"第 %d 组的 %s 同学的得分排在倒数第 %d 名。",
			        stum_used[iRndStu].stu.group,
			        stum_used[iRndStu].stu.name,
			        iStuCount-iRndStu);
			break;
		}
		case 4: {
			int iRndStu1=0,iRndStu2=0;
			srand(time(NULL)+clock());
			iRndStu1=rand()%iStuCount;
			srand(time(NULL)*clock());
			iRndStu2=rand()%iStuCount;
			sprintf(szTmp,"%s 同学的分数比 %s 同学%s %.1f 分。",
			        stum_used[iRndStu1].stu.name,
			        stum_used[iRndStu2].stu.name,
			        (stum_used[iRndStu1].dMark>=stum_used[iRndStu2].dMark)?"高":"低",
			        (stum_used[iRndStu1].dMark>=stum_used[iRndStu2].dMark)?
			        (stum_used[iRndStu1].dMark-stum_used[iRndStu2].dMark):
			        (stum_used[iRndStu2].dMark-stum_used[iRndStu1].dMark));

			break;
		}
	}
	sprintf(szRst,szTmp);
}

int GetTips(char szGet[300]) {
	const char *szTips[100]= {
		"请关注 https://gitee.com/emmm-233/class-log-2.0/releases 获取程序更新！",
		"请关注 https://gitee.com/emmm-233/class-log-2.0/releases 获取程序更新！",
		"请关注 https://gitee.com/emmm-233/class-log-2.0/releases 获取程序更新！",
		"在记录日志的时候，程序会自动加载当天日期。",
		"打开“将分数算到整个小组”可以不用填写“姓名”一栏而将分数算到整个小组。",
		"打开“批量记录日志”可以一次性记录多条日志，这些日志有相同的日期、分数和原因。",
		"在批量记录打开时，将无法在主界面设置“将分数算到整个小组”和“通过名单自动填充小组”选项。",
		"你可以将常用的原因添加到“快捷原因”。",
		"真的有人会想删除“数学作业”这个快捷原因吗？",
		"自己用记事本修改日志文件可能不是一个好主意。",
		"在“查看和修改日志”界面可以将日志导出备份。",
		"如果名单有变动，请在“记录日志”界面点击 操作>重载名单。",
		"在你保存修改前，删除日志的操作可以被撤销。",
		"确认清空日志后，它们会永久失去（真的很久）！",
		"导入1.0版本的日志是不受支持的操作！" ,
		"统计报告仅展示每个小组的总分及排名，统计明细可以具体到每个人。",
		"没事别去按“设置”界面的“调试”按钮...",
		"Windows 10 1803 之前的系统版本不支持 DPI 感知功能，这可能导致程序看起来比较模糊。",
		"预览版程序，出现各种离谱 bug 都是正常的，接受它...",
		"程序最多只能存储和加载 999 条日志，如果装满了记得及时导出并清空。",
		"名单导入向导中出现的“小Joker”是作者班上的一个小梗。",
		"即使 .classlog 是作者自己创造的文件格式，里面的数据都是普通的文本文档格式。",
		"本程序可操作的所有表格文件都是 .csv 文件，它其实有一定的局限性。",
		"设置里面有“显示状态栏”的选项，但状态栏中的信息对普通用户而言没有用。",
		"有些东西看起来像是静态的文字，实际上它们可能是只读的编辑框...",
		"如果真的不想导入名单，可以在设置或向导界面中关闭向导自动启动。",
		"你可以在 设置>偏好设置 中关闭启动时自动显示程序提示。",
		"在日志记录时会自动保存记录时间，这个时间是不能被手动修改的！",
		"你可以在 设置>偏好设置 中关闭日志自动保存记录时间和修改时间的选项。",
		"日志的记录时间、修改时间和你自己填写的日志“日期”不是一个意思。",
		"如果要进行修改名单或快捷原因、批量记录等操作，请转到“记录日志”页面。",
		"你可以在 设置>偏好设置 中修改程序启动时打开的标签页。",
		"不要手滑记录了重复的日志！",
		"真的会有人把“设置”设成启动标签页吗？",
		"查看界面的日志可以有不同的排序方式，点击右上角的“排序”按钮。",
		"搜索日志时可以加上一些修饰词限定搜索范围。如\"name:\"表示姓名。",
		"班级公告的“特大”字号和程序标签页的标题是一样大的。",
		"在没有名单的时候，“点名”功能会随机抽学号，当然有名单的时候也可以设置这样抽。",
		"字号设置为小的班级公告真的有人能看清吗？",
		"在百宝箱中才能编辑班级公告！",
		"作者是个 joker..."
	};
	int iStrMax=0;
	for(int i=0; i<=99; i++) {
		if(szTips[i]!=NULL)iStrMax++;
	}
	srand(time(NULL)+clock());
	int iRand=rand()%iStrMax;
	strcpy(szGet,szTips[iRand]);
	return iRand;
}

bool AreLogsTheSame(LOG log1,LOG log2) {
	if(log1.mark!=log2.mark)return false;
	if(strcmp(log1.rsn,log2.rsn))return false;
	if(log1.logdate.y!=log2.logdate.y)return false;
	if(log1.logdate.m!=log2.logdate.m)return false;
	if(log1.logdate.d!=log2.logdate.d)return false;
	if(strcmp(log1.logstu.name,log2.logstu.name))return false;
	if(log1.logstu.group!=log2.logstu.group)return false;
	return true;
}

//返回值：是否即将被删除
int AddLogToLV(HWND hlList,int i,LOG log) {
	LvAddItemF(hlList,i,0,"%d/%d/%d",
	           log.logdate.y,log.logdate.m,log.logdate.d);
	LvSetItemF(hlList,i,1,"%s",log.logstu.name);
	LvSetItemF(hlList,i,2,"%d",log.logstu.group);
	LvSetItemF(hlList,i,3,"%+.1f",log.mark);
	LvSetItemF(hlList,i,4,"%s",log.rsn);

	tm ctmRecord,ctmLastEdit;
	ctmRecord=*localtime(&log.tRecordTime);
	ctmLastEdit=*localtime(&log.tLastEditTime);

	LvSetItemF(hlList,i,5,"%d/%d/%d %02d:%02d",
	           ctmRecord.tm_year+1900,
	           ctmRecord.tm_mon+1,
	           ctmRecord.tm_mday,
	           ctmRecord.tm_hour,ctmRecord.tm_min);
	if(log.tRecordTime==0) {
		LvSetItemF(hlList,i,5,"(无信息)");
	}

	LvSetItemF(hlList,i,6,"%d/%d/%d %02d:%02d",
	           ctmLastEdit.tm_year+1900,
	           ctmLastEdit.tm_mon+1,
	           ctmLastEdit.tm_mday,
	           ctmLastEdit.tm_hour,ctmLastEdit.tm_min);
	if(log.tLastEditTime==0) {
		LvSetItemF(hlList,i,6,"(无信息)");
	}

	if(log.bToBeDel) {
		LvSetItemF(hlList,i,0,"[!] 保存后将被删除");
		LvSetItemF(hlList,i,1,"");
		LvSetItemF(hlList,i,2,"");
		LvSetItemF(hlList,i,3,"");
		LvSetItemF(hlList,i,4,"");
		LvSetItemF(hlList,i,5,"");
		LvSetItemF(hlList,i,6,"");
		return 1;
	}
	return 0;
}

bool IsLog1DateAfterLog2(LOG log1,LOG log2) {
	int iDate1=log1.logdate.y*10000+log1.logdate.m*100+log1.logdate.d,
	    iDate2=log2.logdate.y*10000+log2.logdate.m*100+log2.logdate.d;
	if(iDate1>iDate2)return true;
	else return false;
}

int WriteResetScript() {
	char tmp[260]= {0};
	GetModuleFileName(NULL,tmp,260);
	FILE *pBat=fopen("reset.bat","w");
	if(pBat!=NULL) {
		fprintf(pBat,"@echo off\n");
		fprintf(pBat,"title 班级日志 - 正在重置程序数据...\n");
		fprintf(pBat,"del /s /f /q %s\n",CONFIG);
		fprintf(pBat,"del /s /f /q %s\n",FIRSTUSE);
		fprintf(pBat,"del /s /f /q %s\n",LOGFILE);
		fprintf(pBat,"del /s /f /q %s\n",NAMELIST);
		fprintf(pBat,"del /s /f /q %s\n",FASTRSN);
		fprintf(pBat,"del /s /f /q %s\n",STA_OUT);
		fprintf(pBat,"del /s /f /q %s\n",RAND_STU_CONFIG_FILENAME);
		fprintf(pBat,"del /s /f /q %s\n",CLASS_NOTIFICATION_CONFIG_FILENAME);
		fprintf(pBat,"title 重置完毕，程序即将重启...\n");
		fprintf(pBat,"start %s\n",tmp);
		fprintf(pBat,"del /s /f /q %%0\n");
		fprintf(pBat,"exit");
	} else {
		return -1;
	}
	fclose(pBat);
	return 0;
}

//clog 1.x support

int ConvertLog_OldVersionSupport(char szFileName[MAX_PATH],LOG logNew[500]) {
	int i=0,p=0;
	char get[2000][200],data[2000][200],*tmp,bfr[300];
	FILE *test=fopen(szFileName,"r");
	if(test==nullptr) {
		return 114514;
	}
	while(!feof(test)) {
		fgets(get[i],200,test);
		i++;
	}
	fclose(test);
	i--;
	//数据分割到data中
	for(int j=0; j<=i; j++) {
		p=5*j;
		tmp = strtok(get[j], "\",\"");
		while (tmp != NULL) {
			strcpy(data[p],tmp);
			tmp = strtok(NULL, "\",\"");
			p++;
		}
	}

//data中的数据：
//data[5n]=姓名
//data[5n+1]=小组
//data[5n+2]=日期
//data[5n+3]==分数
//data[5n+4]=原因

//存储

	char buffer[300];
	int q=0;
	for(q=5; q<=5*i; q++) {
		if(q/5>=499)break;
		switch(q%5) {
			case 0: { //名字
				strcpy(logNew[q/5-1].logstu.name,data[q]);
				break;
			}
			case 1: { //小组
				sscanf(data[q],"%d",&logNew[q/5-1].logstu.group);
				break;
			}
			case 2: { //日期
				sscanf(data[q],"%d/%d/%d",
				       &logNew[q/5-1].logdate.y,
				       &logNew[q/5-1].logdate.m,
				       &logNew[q/5-1].logdate.d);
				break;
			}
			case 3: { //分数
				sscanf(data[q],"%lf",&logNew[q/5-1].mark);
				break;
			}
			case 4: {
				strcpy(logNew[q/5-1].rsn,data[q]);
				break;
			}
		}
	}

	for(int n=0; n<=i; n++) {
		logNew[i].tRecordTime=logNew[i].tLastEditTime=0;
	}
	return i;
}
